using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace Hiranipra
{
	public enum ConfigStatus
	{
		Success,
		NotFound,
		BadFormat,
		IOError,
	}

	public class ConfigFile
	{
		private string _fileName;
		private List<string> _groupNames = new List<string>();
		private List<List<KeyValuePair<string, string>>> _settings = new List<List<KeyValuePair<string, string>>>();

		private ConfigFile() { }

		public string FileName { get { return _fileName; } }

		public void Clear()
		{
			_groupNames.Clear();
			_settings.Clear();
		}

		public string this[ string groupName, string key ]
		{
			get
			{
				int groupIndex = this.FindGroupIndex( groupName );
				if( groupIndex == -1 )
					return null;
				else
					return this.FindValue( groupIndex, key );
			}
			set
			{
				int groupIndex = this.FindGroupIndex( groupName );
				if( groupIndex == -1 )
				{
					_groupNames.Add( groupName );
					_settings.Add( new List<KeyValuePair<string, string>>() );
					groupIndex = _groupNames.Count - 1;
				}
				this.SetValue( groupIndex, key, value );
			}
		}

		#region Helpers

		private int FindGroupIndex( string groupName )
		{
			for( int n = 0; n < _groupNames.Count; n++ )
			{
				if( _groupNames[ n ] == groupName )
					return n;
			}
			return -1;
		}

		private string FindValue( int groupIndex, string key )
		{
			List<KeyValuePair<string, string>> groupSettings = _settings[ groupIndex ];
			for( int n = 0; n < groupSettings.Count; n++ )
			{
				if( groupSettings[ n ].Key == key )
					return groupSettings[ n ].Value;
			}
			return null;
		}

		private void SetValue( int groupIndex, string key, string value )
		{
			List<KeyValuePair<string, string>> groupSettings = _settings[ groupIndex ];
			for( int n = 0; n < groupSettings.Count; n++ )
			{
				if( groupSettings[ n ].Key == key )
				{
					groupSettings[ n ] = new KeyValuePair<string, string>( key, value );
					return;
				}
			}
			groupSettings.Add( new KeyValuePair<string, string>( key, value ) );
		}

		#endregion

		#region File Management/Load/Save

		public static ConfigFile Create( string fileName )
		{
			ConfigFile configFile = new ConfigFile();
			configFile._fileName = fileName;
			return configFile;
		}

		public static ConfigStatus Delete( string fileName )
		{
			try
			{
				if( File.Exists( fileName ) == false )
					return ConfigStatus.NotFound;
				File.Delete( fileName );
			}
			catch( Exception ex )
			{
				Debug.WriteLine( "ConfigFile::Delete: file error " + ex.ToString() );
				return ConfigStatus.IOError;
			}
			return ConfigStatus.Success;
		}

		public static ConfigFile Open( string fileName )
		{
			ConfigFile configFile = new ConfigFile();
			configFile._fileName = fileName;
			return configFile;
		}

		public ConfigStatus Load()
		{
			return this.Load( _fileName );
		}

		public ConfigStatus Load( string fileName )
		{
			_fileName = fileName;

			string[] allLines;
			try
			{
				if( File.Exists( fileName ) == false )
					return ConfigStatus.NotFound;
				allLines = File.ReadAllLines( fileName );
			}
			catch( Exception ex )
			{
				Debug.WriteLine( "ConfigFile::Load: file error " + ex.ToString() );
				return ConfigStatus.IOError;
			}

			List<KeyValuePair<string, string>> groupSettings = null;
			foreach( string line in allLines )
			{
				if( line[ 0 ] == '[' )
				{
					_groupNames.Add( line.Substring( 1, line.Length - 2 ) );
					groupSettings = new List<KeyValuePair<string, string>>();
					_settings.Add( groupSettings );
				}
				else
				{
					Debug.Assert( groupSettings != null );
					if( groupSettings == null )
						return ConfigStatus.BadFormat;
					int equalIndex = line.IndexOf( '=' );
					Debug.Assert( equalIndex >= 0 );
					if( equalIndex < 0 )
						return ConfigStatus.BadFormat;
					string value = line.Substring( equalIndex + 1 );
					if( value == "{null}" )
						value = null;
					groupSettings.Add( new KeyValuePair<string, string>( line.Substring( 0, equalIndex ), value ) );
				}
			}

			return ConfigStatus.Success;
		}

		public ConfigStatus Save()
		{
			return this.Save( _fileName );
		}

		public ConfigStatus Save( string fileName )
		{
			_fileName = fileName;

			StringBuilder sb = new StringBuilder();
			for( int groupIndex = 0; groupIndex < _groupNames.Count; groupIndex++ )
			{
				string groupName = _groupNames[ groupIndex ];
				List<KeyValuePair<string, string>> groupSettings = _settings[ groupIndex ];

				Debug.Assert( groupName.Contains( "[" ) == false );
				Debug.Assert( groupName.Contains( "]" ) == false );
				sb.AppendLine( '[' + groupName + ']' );
				foreach( KeyValuePair<string, string> setting in groupSettings )
				{
					Debug.Assert( setting.Key.Contains( "=" ) == false );
					sb.AppendLine( setting.Key + '=' + ( setting.Value ?? "{null}" ) );
				}
			}

			try
			{
				File.WriteAllText( fileName, sb.ToString() );
			}
			catch( Exception ex )
			{
				Debug.WriteLine( "ConfigFile::Save: file error " + ex.ToString() );
				return ConfigStatus.IOError;
			}

			return ConfigStatus.Success;
		}

		#endregion
	}
}
